package com.easykoo.ioc;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

import com.easykoo.ioc.Exception.BeanWireException;
import com.easykoo.ioc.Exception.NoSuchBeanException;
import com.easykoo.ioc.property.PropertyBeanFactory;
import com.easykoo.ioc.xml.XMLBeanFactory;

public abstract class BeanFactory {

	public static BeanFactory getBeanFactory(String type) {
		if ("XML".equalsIgnoreCase(type)) {
			return XMLBeanFactory.getInstance();
		} else if ("properties".equalsIgnoreCase(type)) {
			return PropertyBeanFactory.getInstance();
		}
		return null;
	}

	public abstract Map<String, Object> getEntryMap();

	public abstract void push(Map<String, Object> map);

	public abstract Object getBean(String beanName) throws NoSuchBeanException,
			BeanWireException;

	public Object getBeanByName(String beanName) throws NoSuchBeanException,
			BeanWireException {
		try {
			if (getEntryMap().containsKey(beanName)) {
				Entry entry = (Entry) getEntryMap().get(beanName);
				Object beanObject = Class.forName(entry.getClazz())
						.newInstance();
				Method[] methods = beanObject.getClass().getMethods();
				int length = methods.length;
				for (int i = 0; i < length; i++) {
					String methodName = methods[i].getName();
					if ("set".equals(methodName.substring(0, 3))) {
						String targetBean = methodName.substring(3, 4)
								.toLowerCase() + methodName.substring(4);
						if (getEntryMap().containsKey(targetBean)) {
							Object targetObject = getBean(targetBean);
							methods[i].invoke(beanObject, targetObject);
						}
					}
				}
				return beanObject;
			} else {
				throw new NoSuchBeanException(beanName);
			}
		} catch (InstantiationException e) {
			throw new BeanWireException(e);
		} catch (IllegalAccessException e) {
			throw new BeanWireException(e);
		} catch (ClassNotFoundException e) {
			throw new BeanWireException(e);
		} catch (InvocationTargetException e) {
			throw new BeanWireException(e);
		}
	}

	public Object getBeanByName(Entry entry) throws NoSuchBeanException,
			BeanWireException {
		try {
			Object beanObject = Class.forName(entry.getClazz()).newInstance();
			Method[] methods = beanObject.getClass().getMethods();
			int length = methods.length;
			for (int i = 0; i < length; i++) {
				String methodName = methods[i].getName();
				if ("set".equals(methodName.substring(0, 3))) {
					String targetBean = methodName.substring(3, 4)
							.toLowerCase() + methodName.substring(4);
					if (getEntryMap().containsKey(targetBean)) {
						Object targetObject = getBean(targetBean);
						methods[i].invoke(beanObject, targetObject);
					}
				}
			}
			return beanObject;
		} catch (InstantiationException e) {
			throw new BeanWireException(e);
		} catch (IllegalAccessException e) {
			throw new BeanWireException(e);
		} catch (ClassNotFoundException e) {
			throw new BeanWireException(e);
		} catch (InvocationTargetException e) {
			throw new BeanWireException(e);
		}
	}
}
